/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.jms;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import javax.jms.Destination;
import javax.jms.JMSException;
/**
   This class snapshots the headers that are contained in a JMS message.
   
   @author Shrideep Pallickara
   $Revision$
   $Date$
*/

public class JmsHeader implements JmsDebugFlags{
  /** The JMS messageID */
  private String jmsMessageID="";
  
  /** The timestamp associated with this message */
  private long jmsTimestamp=0;
  
  /** The correlation ID as bytes for this message */
  private byte[] jmsCorrelationIDBytes; 

  /** The correlation ID as a String */ 
  private String jmsCorrelationID="";
     
  /** The destination that a responses, to this message, must be sent to */
  private Destination jmsReplyTo;

  /** The destinations associated with the message */
  private Destination jmsDestination;

   /** The jms Delivery mode for this message */
  private int jmsDeliveryMode;
  
  /** An indication if this message is being redelivered */
  private boolean jmsRedelivered = false;

  /** The jms Message Type */
  private String jmsType;
  
  /** The expiration associated with this message */
  private long jmsExpiration;
  
  /** The priority of this message */
  private int jmsPriority;
  
  public JmsHeader() { 
    jmsMessageID = "ges::jms::" + System.currentTimeMillis();
    jmsTimestamp = System.currentTimeMillis();
  }
  
  public String getJMSMessageID() throws JMSException {
    //if (jmsMessageID == null) {
    //  throw new JMSException("MessageID is null and was probably not set " +
    //			     " by the message publisher");
    //}
    return jmsMessageID;
  }
  
  public void setJMSMessageID(String id) throws JMSException {
    //if (id == null) {
    //  throw new JMSException("MessageID is null");
    //}
    jmsMessageID = id;
  }
  
  public long getJMSTimestamp() throws JMSException {
    //if (jmsTimestamp == 0) {
    //  throw new JMSException("The JMS Timestamp was not set by the publisher");
    //}
    return jmsTimestamp;
  }

  public void setJMSTimestamp(long timestamp) throws JMSException {
    //if (timestamp == 0) {
    //  throw new JMSException("Trying to set JMSTimestamp as 0:Invalid");
    //}
    jmsTimestamp = timestamp;
  }

  public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
    //if (jmsCorrelationIDBytes == null) {
    //  throw new JMSException("The JMSCorrelationID is null");
    //}
    return jmsCorrelationIDBytes; 
  }
  
  public void setJMSCorrelationIDAsBytes(byte[] correlationID) 
    throws JMSException {
    //if (correlationID == null) {
    //  throw new JMSException("The JMSCorrelationID is null");
    //}
    jmsCorrelationIDBytes = correlationID;
  }

  public String getJMSCorrelationID() throws JMSException {
    //if (jmsCorrelationID == null) {
    //  throw new JMSException("The JMSCorrelationID is null/ was not set");
    //}
    return jmsCorrelationID;
  }

  public void setJMSCorrelationID(String correlationID) throws JMSException {
    //if (correlationID == null) {
    //  throw new JMSException("The JMSCorrelationID is null");
    //}
    
    if (JmsHeader_Debug) {
      System.out.println("JmsHeader: Setting the JMSCorrelationID to " +
			 correlationID);
    }
    jmsCorrelationID = correlationID; 
  }
  
  public Destination getJMSReplyTo() throws JMSException {
    //if (jmsReplyTo == null) {
    //throw new JMSException("JmsHeader::The ReplyTo Destination was not set");
    //}
    
    if (JmsHeader_Debug) {
      System.out.println("JmsHeader: ACCESSing JMSReplyTo " +
			 jmsReplyTo);
    }
    
    return jmsReplyTo;
  }
  
  public void setJMSReplyTo(Destination replyTo) throws JMSException {
    //if (replyTo == null) {
    //  throw new JMSException("The ReplyTo Destination is NULL");
    //}
    
    if (JmsHeader_Debug) {
      System.out.println("JmsHeader: Setting the JMSReplyTo to " +
    			 replyTo);
    }
    jmsReplyTo = replyTo;
  }
  
  public Destination getJMSDestination() throws JMSException {
    //if (jmsDestination == null) {
    //  throw new JMSException("The JMSDestination was probably not set " +
    //		     " and it is NULL");
    //}
    return jmsDestination;
  }
  
  public void setJMSDestination(Destination destination) throws JMSException {
    /* if (destination == null) {
       throw new JMSException("The JMSDestination is NULL");
       }
       if (JmsHeader_Debug) {
       System.out.println("JmsHeader: Setting the JMSDestination to " +
       destination);
       }
    */
    
    jmsDestination = destination;
  }
  
  public int getJMSDeliveryMode() throws JMSException {
    return jmsDeliveryMode;
  }
  
  
  public void setJMSDeliveryMode(int deliveryMode) throws JMSException {
    jmsDeliveryMode = deliveryMode;
  }
  
  public boolean getJMSRedelivered() throws JMSException {
    return jmsRedelivered;
  }
  
  public void setJMSRedelivered(boolean redelivered) throws JMSException {
    jmsRedelivered = redelivered;
  }

  public String getJMSType() throws JMSException {
    if (jmsType == null) {
      throw new JMSException("The JMSType is null or was not Set");
    }
    return jmsType;
  }
  
  public void setJMSType(String type) throws JMSException {
    if (type == null) {
      throw new JMSException("The specified JMSType is null");
    }
    jmsType = type;
  }
  
  public long getJMSExpiration() throws JMSException {
    /** A value of zero indicates message doesn't expire*/
    return jmsExpiration; 
  }

  public void setJMSExpiration(long expiration) throws JMSException {
    jmsExpiration = expiration;
  }

  public int getJMSPriority() throws JMSException {
    return jmsPriority;
  }

  public void setJMSPriority(int priority) throws JMSException {
    if (priority < 0 || priority > 9) {
      throw new JMSException("JMS priority out of range ");
    }
    jmsPriority = priority;
  }


  public byte[] getBytes() {
    ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
    DataOutputStream dout = new DataOutputStream(baOutputStream);
    byte[] marshalledBytes = null;
    try {
      dout.writeUTF(jmsMessageID); /** message ID */
      dout.writeLong(jmsTimestamp); /** The timestamp */
      dout.writeUTF(jmsCorrelationID); /** The corelation ID */
      /** Marshalling the jmsReplyTo field */
      if (jmsReplyTo == null) {
	dout.writeInt(0);
      } else {
	if (jmsReplyTo instanceof JmsTopic) {
	  byte[] replyToBytes = ((JmsTopic)jmsReplyTo).getBytes();
	  dout.writeInt(replyToBytes.length);
	  dout.write(replyToBytes);
	} else { 
	  System.out.println("Error marshalling jmsReplyTo in JmsHeader");
	}
      }
      
      /** Marshalling the jmsDestination field */
      if (jmsDestination == null) {
	dout.writeInt(0);
      } else {
	if (jmsDestination instanceof JmsTopic) {
	  byte[] destinationBytes = 
	    ((JmsTopic)jmsDestination).getBytes();
	  dout.writeInt(destinationBytes.length);
	  dout.write(destinationBytes);
	} else { 
	  System.out.println("Error marshalling jmsDestination in JmsHeader");
	}
      }
      
      dout.writeInt(jmsDeliveryMode);
      dout.writeBoolean(jmsRedelivered);
      dout.writeUTF(jmsType);
      dout.writeLong(jmsExpiration);
      dout.writeInt(jmsPriority);

      dout.flush();
      marshalledBytes = baOutputStream.toByteArray();
    } catch (IOException ioe) {
      System.out.println("JmsHeader: IOException during marshalling" + ioe);
    }
    return marshalledBytes;
  }

  public JmsHeader(byte[] headerBytes) {
    ByteArrayInputStream baInputStream = new ByteArrayInputStream(headerBytes);
    DataInputStream din = new DataInputStream(baInputStream);
    
    try {
      jmsMessageID = din.readUTF();
      jmsTimestamp = din.readLong();
      jmsCorrelationID = din.readUTF();

       /** UnMarshalling the jmsReplyTo field */
      int _destLength = din.readInt();
      if (_destLength != 0) {
	byte[] replyToBytes = new byte[_destLength];
	din.readFully(replyToBytes);
	jmsReplyTo = new JmsTopic(replyToBytes);
      }
      
      /** UnMarshalling the jmsDestination field */
      _destLength = din.readInt();
      if (_destLength != 0) {
	byte[] destinationBytes = new byte[_destLength];
	din.readFully(destinationBytes);
	jmsDestination = new JmsTopic(destinationBytes);
      }

      jmsDeliveryMode = din.readInt();
      jmsRedelivered  = din.readBoolean();
      jmsType = din.readUTF();
      jmsExpiration = din.readLong();
      jmsPriority = din.readInt();
    } catch (IOException ioe) {
      System.out.println("JmsHeader: IOException during marshalling" + ioe);
    } /*end try-catch block */
  } /*end-method*/
  
  public String toString() {
    String headerRep = "JMSHeader Information:: " + 
      " JMSMessageID=(" + jmsMessageID + 
      ") JMSTimeStamp=(" + jmsTimestamp + 
      ") JMSCorrelationID=(" + jmsCorrelationID +
      ") JMSReplyTo= (" + jmsReplyTo +
      ") JMSDestination=( " + jmsDestination +
      ") JMSDeliveryMode=(" + jmsDeliveryMode +
      ") JMSRedelivered=(" + jmsRedelivered +
      ") JMSType=(" + jmsType +
      ") JMSExpiration=(" + jmsExpiration +
      ") JMSPriority=(" + jmsPriority + ")";
    return headerRep;
  }
  
  public static void main(String[] args) {
    JmsHeader header = new JmsHeader();
  
    try {
      header.setJMSMessageID("Shrideep's Test Header");
      header.setJMSTimestamp(System.currentTimeMillis());
      header.setJMSCorrelationID("Wizards-Bulls-Jordan");
      header.setJMSType("CoolType");
      header.setJMSExpiration((long)20);
      header.setJMSPriority(2);
    } catch (JMSException jmsEx) {
      System.out.println("Some error initializing header " + jmsEx);
    }
    byte[] headerBytes = header.getBytes();
    System.out.println("Marshalling complete");
    System.out.println(new JmsHeader(headerBytes));

  }
}






